/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package findAntlrRules;

import gettree.TreeNode;
import interfaceAndController.Controller;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import transformGrammar.SplitGrammarRule;

/**
 * 
 * @author Vicol Daniel-Ionut
 * Memorarea Informatiilor despre o regula de rescriere 
 * 
 * name - identificatorul regulei
 * list - regulile folosite in parsare
 * start - index start a reguluii (in gramatica de intrare)
 * stop - index stop a regului (in fisierul gramaticii date ca input)
 * grammarRule - corpul regulii de parsare
 * subRules - rubregulile disjuncte
 * subRulesRewrite - regula de rescriere a fiecarei subregului
 * posRewrites - multimea posibilitatilor de rescriere
 * map - maparea fiecarei posibile rescrieri la numarul sau de aparitii c find posibila rescriere
 */
public class AntlrRule {
	private static String grammarFile;

	public static HashMap<String,String> Tokens = new HashMap<String, String>(); 


	private String name;
	private ArrayList<String> list = new ArrayList<String>();
	private int start;
	private int stop;
	private String grammarRule;
	private String[] subRules;
	ArrayList<String> subRulesRewrite = new ArrayList<String>();    
	private ArrayList<RewriteInfo> posRewrites = new ArrayList<RewriteInfo>();
	private HashMap<String, Integer> map = new HashMap<String, Integer>();
	private ArrayList<String> labels = new ArrayList<String>();
	//private HashMap<String, Integer> fii = new HashMap<String, Integer>();
	//public int indice;

	public ArrayList<String> getLabels() {
		return labels;
	}
	public String[] getSubRules() {
		return subRules;
	}
	/**
	 * Adauga informatia la lista curenta de informatii
	 * incrementeaza numarul de aparitii a labelului stocat in informatia curenta
	 * @param info (@see RewriteInfo)information to add  
	 */
	public void addToPosRewrites(RewriteInfo info) {
		try {
			String root = info.getTree().getRoot().getChild(0).getLabel() + "///" + info.getRuleNr();
			if (map.containsKey(root)) {
				int ante = map.get(root);
				map.remove(root);
				map.put(root, ante + 1);
			} else {
				map.put(root, 1);
				posRewrites.add(info);
			}
		} catch (Exception e) {
		}

	}

	/**
	 * Contruirea regulii de rescriere pe baza informatiilor colectate
	 * @return regula de ANTLR de rescriere 
	 */
	public String constructRR() {
		StringBuffer r = new StringBuffer();
		r.append(name );
		r.append( " : ");
		// regula de rescriere pentru fiecare subregula
		for (int i = 0 ; i<subRules.length ;i++){
			r.append("\n\t\t");
			if (i!=0)
				r.append("| ");
			r.append(subRules[i].trim());
			if (labels.size() <1 )
				continue;
			if (!labels.get(i).trim().equals("")){
				if(subRulesRewrite.get(i).trim().equals(""))
					continue;
				String [] fii = subRulesRewrite.get(i).split("///");
				if (fii.length!=0)
					r.append(" -> ^('"+labels.get(i).subSequence(0,labels.get(i).lastIndexOf("///") ).toString().trim() +"' ");
				for (int j = 0 ; j < fii.length ; j++){
					//String [] pos = fii[j].split(" "); 
					//r.append(pos[pos.length-1]);
					if (fii[j].trim().endsWith(";"))
						r.append(fii[j].trim().substring(0,fii[j].trim().length()-2 ));
					else
						r.append(fii[j]);
					r.append(" ");
				}
				if (fii.length!=0)
					r.append(")");
			}

		}
		r.append("\n\t;");
		return r.toString();
	}

	public String getGrammarRule() {
		return grammarRule;
	}

	public void setGrammarRule(String grammarRule) {
		this.grammarRule = grammarRule;
		subRules = SplitGrammarRule.splitRule(SplitGrammarRule.stripRuleName(grammarRule));
	}

	public static String getGrammarFile() {
		return grammarFile;
	}

	public static void setGrammarFile(String _grammarFile) {
		grammarFile = _grammarFile;
	}

	public ArrayList<String> getList() {
		return list;
	}

	public void setList(ArrayList<String> list) {
		this.list = list;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getStart() {
		return start;
	}

	public void setStart(int start) {
		this.start = start;
	}

	public int getStop() {
		return stop;
	}

	public void setStop(int stop) {
		this.stop = stop;
	}

	public void addElement(String element) {
		list.add(element);
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		final AntlrRule other = (AntlrRule) obj;
		if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
			return false;
		}
		return true;
	}

	@Override
	public int hashCode() {
		int hash = 7;
		return hash;
	}

	@Override
	public String toString() {
		return name;
	}


	/**
	 * Analizarea mutimilor de metode de rescriere a fiecarei subreguli
	 * alegerea acelei reguli cu cel mai mare numar de aparitii pentru fiecare subregula
	 * @throws Exception 
	 */
	public static void analyze() throws Exception {
		// analizam toate regulile gramaticii ce au sociate un arbore de la utilizator
		for (int k = Controller.orderedRuleList.size() - 1; k >= 0; k--) {

			AntlrRule r = Controller.orderedRuleList.get(k);

			// cautam eticheta cea mai semnificatia (cu cele mai multe aparitii) pentru fiecare subregula
			String[] subrules = r.getSubRules();
			
			r.subRulesRewrite.clear();
			//eliminam etichetele utilizate pana la momnetul curent
			r.labels.clear();
			//parcurgem lista de subreguli 
			for (int j = 0; j < subrules.length; j++) {
				int max = 0;
				r.subRulesRewrite.add("");
				String ruleNr = r.getName() +"_"+ j;
				
				r.labels.add("");
				// cautam regula cu cel mai mare numar de aparitii si o asociem subregulii
				for (String e : r.map.keySet()) {
					if (e.split("///")[e.split("///").length - 1].equals(ruleNr)) {
						if (max < r.map.get(e)) {
							max = r.map.get(e);
							r.labels.set(j, e);
						}
					}
				}
				// verificam daca subregulii i-a fost asociat un label
				if (r.labels.get(j).equals(""))
					continue;
				StringBuilder f = new StringBuilder(transformGrammar.TransformGrammar.constructTreeWLabel(subrules[j]));
				r.subRulesRewrite.set(j,f.toString());

			}

		}

	}


	/**
	 * Analizarea mutimilor de metode de rescriere a fiecarei subreguli
	 * alegerea acelei reguli cu cel mai mare numar de aparitii pentru fiecare subregula
	 * @throws IOException
	 * @throws NoSuchFieldException 
	 */
	public static void analyze2() {
		// parcurge toate regulele definite in gramatica 
		for (int i =0 ; i < Controller.orderedRuleList.size(); i++){
			AntlrRule currentRule = Controller.orderedRuleList.get(i);
			// verificam daca regula curent analizata are asociata amcar o posibila rescriere de la utilizator
			if(currentRule.posRewrites == null || currentRule.posRewrites.isEmpty()) 
				continue;
			int max = 0 ;
			String[] subrules = currentRule.getSubRules();
			currentRule.subRulesRewrite.clear();
			currentRule.labels.clear();
			// analizam fiecare subregula a regulii curente si determinam labelul 
			for (int j = 0; j < subrules.length; j++) {
				currentRule.subRulesRewrite.add("");
				String ruleNr = currentRule.getName() +"_"+ j;
				// pregatim locul noului label
				currentRule.labels.add("");

				for (String e : currentRule.map.keySet()) {
					// filtram inputul utilizatorului ce nu apartin subregulii curente
					if (e.split("///")[e.split("///").length - 1].equals(ruleNr)) {
						if (max < currentRule.map.get(e)) {
							max = currentRule.map.get(e);
							currentRule.labels.set(j, e);
						}
					}
				}
				// verificam daca ma gadit un pitential label pentru subregula cu indicele j 
				if (currentRule.labels.get(j).equals(""))
					continue;

			}

		}
	}
	/**
	 * Compare current rule with rule
	 * @param rule 
	 * @return 0 - equals  1 - biger -1- smaller
	 */
	public int compare(AntlrRule rule){
		if (this.list.contains(rule.getName())){

			return 1 ; 
		}
		if (rule.list.contains(this.name)){

			return -1 ;
		}

		return 0 ; 

	}


}
